/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/

/**********************************************************\
 *                                                        *
 * hprose/util/Util.cpp                                   *
 *                                                        *
 * some util for cpp.                                     *
 *                                                        *
 * LastModified: Oct 27, 2016                             *
 * Author: Chen fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

#include <hprose/util/Util.h>

#include <limits>

namespace hprose {
namespace util {

const char digits[] =
    "0123456789";

const char digit2[] =
    "0001020304050607080910111213141516171819"
    "2021222324252627282930313233343536373839"
    "4041424344454647484950515253545556575859"
    "6061626364656667686970717273747576777879"
    "8081828384858687888990919293949596979899";

const char digit3[] =
    "000001002003004005006007008009010011012013014015016017018019"
    "020021022023024025026027028029030031032033034035036037038039"
    "040041042043044045046047048049050051052053054055056057058059"
    "060061062063064065066067068069070071072073074075076077078079"
    "080081082083084085086087088089090091092093094095096097098099"
    "100101102103104105106107108109110111112113114115116117118119"
    "120121122123124125126127128129130131132133134135136137138139"
    "140141142143144145146147148149150151152153154155156157158159"
    "160161162163164165166167168169170171172173174175176177178179"
    "180181182183184185186187188189190191192193194195196197198199"
    "200201202203204205206207208209210211212213214215216217218219"
    "220221222223224225226227228229230231232233234235236237238239"
    "240241242243244245246247248249250251252253254255256257258259"
    "260261262263264265266267268269270271272273274275276277278279"
    "280281282283284285286287288289290291292293294295296297298299"
    "300301302303304305306307308309310311312313314315316317318319"
    "320321322323324325326327328329330331332333334335336337338339"
    "340341342343344345346347348349350351352353354355356357358359"
    "360361362363364365366367368369370371372373374375376377378379"
    "380381382383384385386387388389390391392393394395396397398399"
    "400401402403404405406407408409410411412413414415416417418419"
    "420421422423424425426427428429430431432433434435436437438439"
    "440441442443444445446447448449450451452453454455456457458459"
    "460461462463464465466467468469470471472473474475476477478479"
    "480481482483484485486487488489490491492493494495496497498499"
    "500501502503504505506507508509510511512513514515516517518519"
    "520521522523524525526527528529530531532533534535536537538539"
    "540541542543544545546547548549550551552553554555556557558559"
    "560561562563564565566567568569570571572573574575576577578579"
    "580581582583584585586587588589590591592593594595596597598599"
    "600601602603604605606607608609610611612613614615616617618619"
    "620621622623624625626627628629630631632633634635636637638639"
    "640641642643644645646647648649650651652653654655656657658659"
    "660661662663664665666667668669670671672673674675676677678679"
    "680681682683684685686687688689690691692693694695696697698699"
    "700701702703704705706707708709710711712713714715716717718719"
    "720721722723724725726727728729730731732733734735736737738739"
    "740741742743744745746747748749750751752753754755756757758759"
    "760761762763764765766767768769770771772773774775776777778779"
    "780781782783784785786787788789790791792793794795796797798799"
    "800801802803804805806807808809810811812813814815816817818819"
    "820821822823824825826827828829830831832833834835836837838839"
    "840841842843844845846847848849850851852853854855856857858859"
    "860861862863864865866867868869870871872873874875876877878879"
    "880881882883884885886887888889890891892893894895896897898899"
    "900901902903904905906907908909910911912913914915916917918919"
    "920921922923924925926927928929930931932933934935936937938939"
    "940941942943944945946947948949950951952953954955956957958959"
    "960961962963964965966967968969970971972973974975976977978979"
    "980981982983984985986987988989990991992993994995996997998999";

void WriteInt(std::ostream &stream, int64_t i) {
    if (i == 0) {
        stream << '0';
        return;
    }
    if (i == std::numeric_limits<int64_t>::min()) {
        stream << "-9223372036854775808";
        return;
    }
    char sign = '+';
    if (i < 0) {
        sign = '-';
        i = -i;
    }
    char buf[20];
    int off = 20;
    int64_t q, p;
    while (i >= 100) {
        q = i / 1000;
        p = (i - (q * 1000)) * 3;
        i = q;
        off -= 3;
        buf[off] = digit3[p];
        buf[off + 1] = digit3[p + 1];
        buf[off + 2] = digit3[p + 2];
    }
    if (i >= 10) {
        q = i / 100;
        p = (i - (q * 100)) * 2;
        i = q;
        off -= 2;
        buf[off] = digit2[p];
        buf[off + 1] = digit2[p + 1];
    }
    if (i > 0) {
        off--;
        buf[off] = digits[i];
    }
    if (sign == '-') {
        off--;
        buf[off] = sign;
    }
    stream.write(&buf[off], 20 - off);
}

void WriteUint(std::ostream &stream, uint64_t u) {
    if (u == 0) {
        stream << '0';
        return;
    }
    char buf[20];
    int off = 20;
    uint64_t q, p;
    while (u >= 100) {
        q = u / 1000;
        p = (u - (q * 1000)) * 3;
        u = q;
        off -= 3;
        buf[off] = digit3[p];
        buf[off + 1] = digit3[p + 1];
        buf[off + 2] = digit3[p + 2];
    }
    if (u >= 10) {
        q = u / 100;
        p = (u - (q * 100)) * 2;
        u = q;
        off -= 2;
        buf[off] = digit2[p];
        buf[off + 1] = digit2[p + 1];
    }
    if (u > 0) {
        off--;
        buf[off] = digits[u];
    }
    stream.write(&buf[off], 20 - off);
}

void WriteDate(std::ostream &stream, int year, int month, int day) {
    int q = year / 100;
    int p = q << 1;
    stream << digit2[p] << digit2[p + 1];
    p = (year - q * 100) << 1;
    stream << digit2[p] << digit2[p + 1];
    p = month << 1;
    stream << digit2[p] << digit2[p + 1];
    p = day << 1;
    stream << digit2[p] << digit2[p + 1];
}

void WriteTime(std::ostream &stream, int hour, int min, int sec) {
    int p = hour << 1;
    stream << digit2[p] << digit2[p + 1];
    p = min << 1;
    stream << digit2[p] << digit2[p + 1];
    p = sec << 1;
    stream << digit2[p] << digit2[p + 1];
}

int UTF16Length(const std::string &str) {
    int length = str.length();
    int n = length;
    int p = 0;
    while (p < length) {
        char a = str.at(p);
        switch (static_cast<uint8_t>(a) >> 4) {
            case 0:
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
                p++;
                break;
            case 12:
            case 13:
                p += 2;
                n--;
                break;
            case 14:
                p += 3;
                n -= 2;
                break;
            case 15:
                if ((a & 8) == 8) {
                    return -1;
                }
                p += 4;
                n -= 2;
                break;
            default:
                return -1;
        }
    }
    return n;
}

}
} // hprose::util
